package com.zwan.oam_rtc.utils.wintcp;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;


public class MD5 
{
    private static final char[] hexDigits = "0123456789abcdef".toCharArray();
    
	/**
     * 做MD5处理
     * @param bytes 源字节数组
     * @return MD5后处理字节数组，以hex表示
     */
    public static final byte[] doit(byte[] bytes) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(bytes);
            return mdTemp.digest();
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 做MD5处理，字符串将以utf-8编码
     * @param s 源串
     * @return MD5后处理的字符串，以hex表示
     */
    public static final String doit(String s) {
        try {
        	return byte2HexStr(doit(s.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 简单的字符串到十六进制转换
     * @param bytes 源字节数组
     * @return 十六进制字符串
     */
    public static String byte2HexStr(byte[] bytes){
    	return byte2HexStr(bytes, false);
    }
    
    /**
     * 简单的字符串到十六进制转换
     * @param bytes 源字节数组
	 * @param printable 是否插入空格以优化日志打印
     * @return 十六进制字符串
     */
    public static String byte2HexStr(byte[] bytes, boolean printable){
    	if (bytes == null) return null;
    	int j = bytes.length;
//        char[] str = new char[j * 2];
    	StringBuffer sb = new StringBuffer();
        // 二进制转十六进制
        int k = 0;
        for (int i = 0; i < j; i++) {
        	if (printable && k++ % 16 == 0)
        		sb.append("\r\n");
        	byte byte0 = bytes[i];
            sb.append(hexDigits[byte0 >>> 4 & 0xf]).append(hexDigits[byte0 & 0xf]);
//            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
//            str[k++] = hexDigits[byte0 & 0xf];
            if (printable && k % 8 != 0)
            	sb.append(" ");
            if (printable && k % 16 == 8)
            	sb.append("  ");
        }

        return sb.toString();
    }
    
    /**
     * 字节数组编码为Base64字符串
     * @param b 源字节数组
     * @return 编码后的字符串
     */
    // public static String encodeBase64(byte[] b){
    // 	BASE64Encoder encoder = new BASE64Encoder();
    // 	return encoder.encode(b);
    // }
    
    /**
     * 字符串的Base64解码
     * @param s 源字符串
     * @return 解码后的字节数组
     */
    // public static byte[] decodeBase64Str(String s){
    // 	BASE64Decoder decoder = new BASE64Decoder(); 
    // 	byte[] b = null;
	// 	try {
	// 		b = decoder.decodeBuffer(s);
	// 	} catch (IOException e) {
	// 		e.printStackTrace();
	// 	} 
    // 	return b;
    // }

    /**
    * DES 加密算法
    * @param data 处理数据
    * @param key 密钥
    * @param mode 加密：Cipher.ENCRYPT_MODE = 1, 解密：Cipher.DECRYPT_MODE =2，传入2表示解密，否则表示加密
    * @return 加密后的字符串，以Base64编码
    */
    // public static String des(byte[] data, String key, int mode) {
    // 	mode = (mode == Cipher.DECRYPT_MODE)? mode : Cipher.ENCRYPT_MODE;
    //     DESPlus desObj;
	// 	try {
	// 		desObj = new DESPlus(key);
	// 		if (mode == Cipher.ENCRYPT_MODE)
	//         	return encodeBase64(desObj.encrypt(data));
	// 		else
	// 			return desObj.decryptBase64(new String(data));
	// 	} catch (Exception e) {
	// 		e.printStackTrace();
	// 	}
	// 	return null;
    // }
    
    
    /**
     * DES 加密算法
     * @param data 处理数据
     * @param key 密钥
     * @param mode 加密：Cipher.ENCRYPT_MODE = 1, 解密：Cipher.DECRYPT_MODE =2，传入2表示解密，否则表示加密
     * @return 加密后的字符串，以hex编码
     */
    public static String desAsHexStr(byte[] data, String key, int mode) {
    	return desAsHexStr(data, key.getBytes(), mode);
    }
    
    /**
     * DES 加密算法
     * @param data 处理数据
     * @param key 密钥
     * @param mode 加密：Cipher.ENCRYPT_MODE = 1, 解密：Cipher.DECRYPT_MODE =2，传入2表示解密，否则表示加密
     * @return 加密后的字符串，以hex表示
     */
     public static String desAsHexStr(byte[] data, byte[] key, int mode) {
     	mode = (mode == Cipher.DECRYPT_MODE)? mode : Cipher.ENCRYPT_MODE;
     	try {
             Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
             SecretKeySpec spec = new SecretKeySpec(initKey(key), "DES");
             cipher.init(mode, spec);

             byte[] ciphertext;

//             if (mode == Cipher.ENCRYPT_MODE) {
                 ciphertext = cipher.doFinal(data);
//             } else {
//                 BASE64Decoder decoder = new BASE64Decoder();
//                 ciphertext = cipher.doFinal(decoder.decodeBuffer(
//                             new String(data)));
//             }
             String cipertextString = byte2HexStr(ciphertext);
             return cipertextString;
         } catch (Exception e) {
             e.printStackTrace();
             return "";
         }
     }

    //    初始化key，保证密钥的长度是8的倍数
    protected static byte[] initKey(byte[] srcKey) {
        if (srcKey.length == 8) return srcKey;
        byte[] keyBytes = new byte[8];
        System.arraycopy(srcKey, 0, keyBytes, 0, Math.min(keyBytes.length, srcKey.length));
        return keyBytes;
    }
    
    /**
     * 字节数组转换为hex字符串
     * @param b 源字节数组
     * @return 编码后的hex字符串
     */
    public static String bytes2HexString(byte[] b) {
		return byte2HexStr(b);
	}
	
    /**
     * 从十六进制字符串到字节数组转换
     * @param hexstr 源十六进制字符串
     * @return 字节数组
     */
	public static byte[] hexString2Bytes(String hexstr) {
		byte[] b = new byte[hexstr.length() / 2];
		int j = 0;
		for (int i = 0; i < b.length; i++) {
			char c0 = hexstr.charAt(j++);
			char c1 = hexstr.charAt(j++);
			b[i] = (byte) ((parse(c0) << 4) | parse(c1));
		}
		return b;
	}
	
	private static int parse(char c) {
		if (c >= 'a')
			return (c - 'a' + 10) & 0x0f;
		if (c >= 'A')
			return (c - 'A' + 10) & 0x0f;
		return (c - '0') & 0x0f;
	}
	 
	/**
	 * 得到字节数组的BCD编码
	 * @param bs 源字节数组
	 * @return BCD编码字符串
	 */
	public static String getBCDString(byte[] bs){
		 String s = bytes2HexString(bs);
		 int i = s.indexOf("ff");
		 return i >= 0 ? s.substring(0, i) : s;
	}
	
	/**
	 * 将字符串转换为BCD码字节数组，前提是字符串的字符在[0-9a-fA-F]范围内
	 * @param src 
	 * @param desc
	 */
	public static void str2BCDByte(String src, byte[] desc){
		 Arrays.fill(desc, (byte)0xFF);
		 byte[] b1 = hexString2Bytes(src + "FF");
		 System.arraycopy(b1, 0, desc, 0, Math.min(desc.length, b1.length));
	}
	  
	 public static void main1(String[] args){
		 LineNumberReader lr = new LineNumberReader(new InputStreamReader(System.in));
		 String key ;
		 String s;
		 try {
			 System.out.println("请输入key");
			 key = lr.readLine();
			 if (key == null)
				 return;
			 System.out.println("请输入源串: ");
			 s = lr.readLine();
			 while(s != null)
			 {
				 if (s.equals("exit!")){
					 break;
				 }
				 System.out.println(MD5.doit(MD5.doit(s) + key));
				 System.out.println("请输入源串: ");
				 s = lr.readLine();
			 }
		} catch (IOException e) {
			e.printStackTrace();
		}
	 }
	    public static String byte2Base64Str(byte[] bytes){
	    	int j = bytes.length;
	        char[] str = new char[j * 2];
	        // 二进制转十六进制
	        int k = 0;
	        for (int i = 0; i < j; i++) {
	            byte byte0 = bytes[i];
	            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
	            str[k++] = hexDigits[byte0 & 0xf];
	        }

	        return new String(str).trim();
	    }
	 
//	 public static void main(String[] args){
////		 String s1 = desAsHexStr(hexString2Bytes("251e781c00690000251e781c00690000"), hexString2Bytes("8f90ac24955d1b85"), 1);
////		 
////		 System.out.println(s1);
////		 s1 = des("123456".getBytes(), "123456", 1);
////		 System.out.println(s1);
////		 
////		 String s = des(s1.getBytes(), "123456", 2);
////		 System.out.println(s);
////		 DesEncrypt des = new DesEncrypt();// 实例化一个对像
////		 des.getKey(hexString2Bytes("8f90ac24955d1b85"));
////		 s1 = des.getDesStrByHex(s1.substring(0, s1.length() - 16));
////		 
////		 System.out.println(s1);
////		 main1(args);
//		 String s = des("123".getBytes(), "iexsbccs", 1);
//		 System.out.println(s);
//		 System.out.println(des(s.getBytes(), "iexsbccs", 2));
//		
//		 byte []a ={(byte)2,(byte)2,(byte)32,(byte)22,(byte)21};
//		 System.out.println(encodeBase64(a));
//		 System.out.println(byte2Base64Str(a));
//		 System.out.println(MD5.doit("123"));
//	 }
}
